package walletuserslogic

import (
	"context"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go.uber.org/zap"
	"navi-mumbai/app/rpc/model/pg/wallet"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"

	"navi-mumbai/app/rpc/wallet/internal/svc"
	"navi-mumbai/app/rpc/wallet/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateTransferFromGameResultLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateTransferFromGameResultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateTransferFromGameResultLogic {
	return &UpdateTransferFromGameResultLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 更新转入B端钱包结果
func (l *UpdateTransferFromGameResultLogic) UpdateTransferFromGameResult(in *pb.UpdateTransferFromGameResultReq) (*pb.UpdateTransferFromGameResultResp, error) {
	defer utils.RecoverPanic()

	var err error
	var utf *wallet.UserTransferFromGameFlow
	utf, err = l.svcCtx.UserTransferFromGameFlowModel.FindOne(l.ctx, in.FlowNo)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		if err == wallet.ErrNotFound {
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowNotFound, "wallet flow not exist")
		}
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	// 判断是否已经更新过
	if utf.State != walletkey.UserWalletTransferFromGameFlowStateInit {
		l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "wallet flow state error")))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "wallet flow state error")
	}

	// 用户钱包余额
	var dUserWalletBalance decimal.Decimal

	// 更新转账结果
	if in.State == walletkey.UserWalletTransferFromGameFlowStateSuccess { // 转账成功
		// 校验转账结果
		var dNewBalance decimal.Decimal
		dNewBalance, err = decimal.NewFromString(in.NewBalance)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, err.Error())
		}
		var dOldBalance decimal.Decimal
		dOldBalance, err = decimal.NewFromString(in.OldBalance)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, err.Error())
		}
		// 实际转账金额
		dMoneyAmount := dOldBalance.Sub(dNewBalance)
		iMoneyAmount := dMoneyAmount.Mul(decimal.NewFromInt(walletkey.MoneyScale)).RoundFloor(0).IntPart()
		iNewBalance := dNewBalance.Mul(decimal.NewFromInt(walletkey.MoneyScale)).RoundFloor(0).IntPart()

		dUtfMoneyAmount := decimal.NewFromInt(utf.MoneyAmount)
		if !dUtfMoneyAmount.Equal(dMoneyAmount) {
			l.Logger.Errorf("amount not equal, flow MoneyAmount: %v, actual MoneyAmount: %v", utf.MoneyAmount, iMoneyAmount)
		}

		// 获取游戏钱包信息
		var ugw *wallet.UserGameWallet
		ugw, err = l.svcCtx.UserGameWalletModel.FindOneByUidProviderIdMoneyType(l.ctx, utf.Uid, utf.ProviderId, utf.MoneyType)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 获取用户钱包信息
		var uw *wallet.UserWallet
		uw, err = l.svcCtx.UserWalletModel.FindOneByUidMoneyType(l.ctx, utf.Uid, utf.MoneyType)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		dUserWalletBalance = decimal.NewFromInt(uw.Amount)
		dUserWalletBalance = dUserWalletBalance.Add(dMoneyAmount)

		err = l.svcCtx.UserWalletModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
			// 更新用户游戏钱包
			err2 := l.svcCtx.UserGameWalletModel.UpdateMoneyAmountTrans(ctx, tx, ugw.Id, ugw.Uid, ugw.ProviderId, ugw.MoneyType, iNewBalance)
			if err2 != nil {
				l.Logger.Errorf("err == ", zap.Error(err2))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
			}

			// 更新用户钱包
			err2 = l.svcCtx.UserWalletModel.AddAmountTrans(ctx, tx, iMoneyAmount, uw.Id, uw.Uid, uw.MoneyType)
			if err2 != nil {
				l.Logger.Errorf("err == ", zap.Error(err2))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
			}

			// 更新用户转账流水
			err2 = l.svcCtx.UserTransferFromGameFlowModel.UpdateStateTrans(l.ctx, tx, utf.FlowNo, in.ExternalFlowNo, in.State)
			if err2 != nil {
				l.Logger.Errorf("err == ", zap.Error(err2))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
			}
			return nil
		})
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, err
		}
	} else { // 转账失败
		// 更新用户转账流水
		err = l.svcCtx.UserTransferFromGameFlowModel.UpdateState(l.ctx, utf.FlowNo, in.ExternalFlowNo, in.ErrMsg, in.State)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
	}
	var rsp pb.UpdateTransferFromGameResultResp
	rsp.Balance = dUserWalletBalance.Div(decimal.NewFromInt(walletkey.MoneyScale)).StringFixedBank(2)
	rsp.MoneyType = utf.MoneyType
	return &rsp, nil
}
